package org.javia.arity;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class FunctionTest {

	CompiledFunction fIm;
	CompiledFunction fRe;
	CompiledFunction fSumSin;
//	CompiledFunction fGreat;
//	CompiledFunction fCall;
//	Function fsquare;
	Function f7;
	
	@Before
	public void setUp() throws Exception {
		
		
		byte[] db= {1, 1, 38, 5, 3}; //2+2x
		byte[] rest={1,1,38,5,4};
		double[] re={2.0,2.0};
		double[] im={3.0,1.0};
		double[] emptyArray=new double[0];
		Function[] f=new Function[0];
	
//	Symbols s= new Symbols();
	 byte[] sumOfSin={38,17,38,9,18,3}; //sin(x)+cos(-x)
//	 fGreat= (CompiledFunction)s.compile("asinh(1!)+((sin(min(x,y))+cos(-x^2)/max(x,y)%x+sinh(x-e)+cosh(x)+tanh(4)+tanh(x*pi)*atanh(x)*atanh(3i)/acosh(x)-sqrt(y))%4)!");
//	 fCall= (CompiledFunction)s.compile("foo(a, b) = a*(b+1)");

//	 s.define(s.compileWithName("f(x,y)=x^2+y")); 
//	 fCall=(CompiledFunction) s.compile("f(x,y)^4");
//	 fsquare=s.compile("x^2");
	
	 fSumSin= new CompiledFunction(1, sumOfSin,emptyArray, null, f);
	 fIm= new CompiledFunction(1, db, re, im, f);
	 fRe= new CompiledFunction(1,db,re,null,f);
	 f7=new CompiledFunction(1,rest,re,null,f);
	 
	}
	
	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testArity() {
	assertEquals(1,fIm.arity());

	}

//	@Test
	public void testEvalDoubleArrayEval() {
		double[] d= {1};
		assertEquals(Double.NaN,fIm.eval(d),0.0001);
		assertEquals(4,fRe.eval(d),0.0001);
		assertEquals(0,f7.eval(d),0.0001);
	}

//	@Test
	public void testToString() {
		assertEquals("arity 1; const (2.0, 3.0); const (2.0, 1.0); load0; mul; add; ",fIm.toString());
	}


	@Test(expected=ArityException.class)
	public void testEval() {
		fIm.eval();
	}

//	@Test
	public void testEvalDouble() {
		assertEquals(Double.NaN,fIm.eval(1.0),0.0001);
	}

//	@Test(expected=ArityException.class)
	public void testEvalDoubleDouble() {
		fIm.eval(2, 1);
	}
	
	

//	@Test
	public void testEvalComplex() {
		assertEquals(new Complex(3,6),fIm.eval(new Complex(1,1)));
	}

//	@Test(expected=ArityException.class)
	public void testEvalComplex1() {
	fIm.evalComplex();
	}

//	@Test(expected=ArityException.class)
	public void testEvalComplexComplex() {
		fIm.eval(new Complex(1,2), new Complex(1,3));
	}

//	@Test(expected=ArityException.class)
	public void testEvalComplexArray() {
		Complex[] c= {new Complex(1,1), new Complex(1,1)};
		fIm.eval(c);
	}

//	@Test
	public void testToComplex() {
		assertEquals(new Complex(3,6),fIm.eval(new Complex(1,1)));
	}

	@Test
	public void testEvalDoubleEvalContext() throws SyntaxException {

//	assertEquals(1.381773,fSumSin.eval(new Complex(1,0).re),0.0001);
//	assertEquals(Double.NaN,fSumSin.eval(new Complex(Double.NaN,Double.POSITIVE_INFINITY).re),0.0001);
//	assertEquals(new Complex(0.0,0),fSumSin.eval(new Complex(Double.POSITIVE_INFINITY,0)));
//	assertEquals(0,fSumSin.eval(Double.POSITIVE_INFINITY),0.0001);
//	assertEquals(Double.NaN,fSumSin.eval(Double.NaN),0.0001);
//	double[] a={6.3,7.6};
//	assertEquals(Double.NaN,fGreat.eval(a),0.0001);
//	assertEquals(5001234.933604,fCall.eval(a),0.0001);
//	Function fder=fsquare.getDerivative();
//	Symbols s= new Symbols();
//	s.define("deri", fder);
//	Function f=s.compile("deri(x)");
//	assertEquals(112.0,f.eval(56),0.0001);
	
//	assertEquals(10,s.compile("gcd(90,10").eval(),0.0001);
//	assertEquals(0,s.compile("comb(5,6)").eval(),0.0001);
//	assertEquals(0,s.compile("perm(5,6)").eval(),0.0001);
//	assertEquals(1,s.compile("mod(10,3)").eval(),0.0001);
//	assertEquals(56,s.compile("abs(-56)").eval(),0.0001);
//	assertEquals(23,s.compile("floor(23.99999)").eval(),0.0001);
//	assertEquals(57,s.compile("ceil(56.11111)").eval(),0.0001);
//	assertEquals(-1,s.compile("sign(-4)").eval(),0.0001);
//	assertEquals(Double.NaN,s.compile("sign(4-3i)").eval(),0.0001);
//	assertEquals(5,s.compile("cbrt(125)").eval(),0.0001);
//	byte[] by= {1,21};
//	double[] d={0.4};
//	Function f9= new CompiledFunction(0, by, d, null, null);
//	assertEquals(1.15927,f9.eval(),0.0001);
//	byte[] by2={1,20};
//	f9= new CompiledFunction(0, by2, d, null, null);
//	assertEquals(0.4115168,f9.eval(),0.0001);
//	byte[] by3={1,13};
//	f9= new CompiledFunction(0, by3, d, null, null);
//	assertEquals(0.632455,f9.eval(),0.0001);
	
	}
	
//	@Test(expected=SyntaxException.class)
	public void testEvalBadSyntax() throws SyntaxException{
		Symbols s= new Symbols();
		s.compile("toma chango tu banana");
	}

//	@Test
	public void testEvalDoubleDoubleEvalContext() {
		fail("Not yet implemented");
	}

//	@Test
	public void testEvalComplexEvalContext() {
		fail("Not yet implemented");
	}

//	@Test
	public void testEvalComplexComplexEvalContext() {
		fail("Not yet implemented");
	}


//	@Test
	public void testGetDerivate(){ //ugly, but the derivate of 2+2x is 2 always
		Function f=fIm.getDerivative();
			assertEquals(3E12+2,f.eval(0),0.0001);
		
	}

//	@Test
	public void testCheckArity() {
		fIm.checkArity(1);
		try {
			fIm.checkArity(2);
			fail();
		} catch (ArityException e) {
		}
	}

//	@Test(expected=Error.class)
	public void testMakeOp(){
		Function f=CompiledFunction.makeOpFunction(2);
	}
//	@Test
	public void testMakeOp2(){
		Function f= CompiledFunction.makeOpFunction(9);
		Function f2= CompiledFunction.makeOpFunction(29);
	
		Function f3= f2.getDerivative();
		assertEquals(1,f3.arity());
		assertEquals(-1,f3.eval(-1.0),0.0001);
		assertEquals(1,f3.eval(1.0),0.0001);
		assertEquals(0,f3.eval(0.0),0.0001);
		
		
	}
	
	
}
